package com.atguigu.crowd.mvc.handler;

import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.exception.LoginAcctAlreadyInUseException;
import com.atguigu.crowd.mapper.bean.Admin;
import com.atguigu.crowd.service.api.AdminService;
import com.atguigu.crowd.util.ResultEntity;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.List;

@Controller
public class AdminHandler {

    @Autowired
    private AdminService adminService;
    //创建日志类，方便程序进行打印调试
    private static final Logger logger = LoggerFactory.getLogger(AdminHandler.class);

    //管理员登陆功能
    @RequestMapping("/admin/do/login.html")
    public String doLogin(@RequestParam("loginAcct")String loginAcct,
                          @RequestParam("userPswd") String userPswd, HttpSession Session) {
        //调用Service方法执行登陆检查
        //这个方法如果能够返回admin对象说明登陆成功，如果账号、密码不正确则会抛出异常
        Admin admin = adminService.getAdminByLoginAcct(loginAcct, userPswd);

        //将登陆成功返回的admin对象存入session域
        Session.setAttribute(CrowdConstant.ATTR_NAME_LOGIN_ADMIN, admin);
        return "redirect:/admin/to/main/page.html";
    }

    //管理员退出后台系统
    @RequestMapping("/admin/do/logout.html")
    public String doLogout(HttpSession Session) {
        Session.invalidate(); //释放session，返回登陆页面
        return "redirect:/admin/to/login/page.html";
    }


    //查询所有admin信息
    @RequestMapping("/admin/get/page.html")
    public String getPageInfo(
            // 使用@RequestParam注解的defaultValue属性，指定默认值，在请求中没有携带对应参数时使用默认值
            //keyword默认值使用空字符串，和SQL语句配合实现两种情况适配
            @RequestParam(value = "keyword", defaultValue = "") String keyword,
            //pageNum默认值使用1
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
            //pageSize默认值使用5
            @RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize,
            ModelMap modelMap
    ) {
        //调用Service方法获取PageInfo对象
        PageInfo<Admin> pageInfo = adminService.getPageInfo(keyword, pageNum, pageSize);
        //将PageInfo对象存入模型，html调用
        modelMap.addAttribute(CrowdConstant.ATTR_NAME_PAGE_INFO, pageInfo);
        logger.info("--------------成功返回admin对象--------------");
        return "admin-page";
    }

    //删除admin
    @RequestMapping("/admin/remove/{adminId}/{pageNum}/{keyword}.html")
    public String remove(
            @PathVariable("adminId") Integer adminId,
            @PathVariable("pageNum") Integer pageNum,
            @PathVariable("keyword") String keyword
    ) {

        // 执行删除
        adminService.remove(adminId);
        logger.info("--------------成功删除admin对象--------------");

        // 页面跳转：回到分页页面

        // 尝试方案1：直接转发到admin-page.jsp 会导致数据无法更新，会无法显示分页数据
        // return "admin-page";

        // 尝试方案2：转发到/admin/get/page.html地址，一旦刷新页面会重复执行删除浪费性能
        // return "forward:/admin/get/page.html";

        // 尝试方案3：重定向到/admin/get/page.html地址，重定向相当于再走一次页面，再查一次数据
        // 同时为了保持原本所在的页面和查询关键词再附加pageNum和keyword两个请求参数
        return "redirect:/admin/get/page.html?pageNum="+pageNum+"&keyword="+keyword;
    }

    @PreAuthorize("hasAnyAuthority('user:save')")
    //添加admin
    @RequestMapping("/admin/save.html")
    public String save (Admin admin) {
        try{
            adminService.saveAdmin(admin);
        }catch (Exception e){
            e.printStackTrace();
            if (e instanceof DuplicateKeyException) {
                throw new LoginAcctAlreadyInUseException(CrowdConstant.MESSAGE_LOGIN_ACCT_ALREADY_IN_USE);
            }
        }
        //重定向到用户页，并定位到最后一页（因为新加的数据在最后一页）
        return "redirect:/admin/get/page.html?pageNum="+Integer.MAX_VALUE;
    }


    //点击修改admin按钮时跳转修改页面，需要在表单回显数据
    @RequestMapping("/admin/to/edit/page.html")
    public String toEditPage (@RequestParam("adminId") Integer adminId, ModelMap modelMap) {
        //通过id获取admin对象
        Admin admin = adminService.getAdminById(adminId);
        //将admin对象添加到modelMap模型中
        modelMap.addAttribute("admin", admin);
        //跳转到admin-edit
        return "admin-edit";
    }

    //修改admin
    @RequestMapping("/admin/update.html")
    public String update (Admin admin,
                          @RequestParam("pageNum") Integer pageNum,
                          @RequestParam("keyword") String keyword) {
        adminService.update(admin);
        return "redirect:/admin/get/page.html?pageNum="+pageNum+"&keyword="+keyword;
    }


    //<========================扩充内容========================>


    //@PostAuthorize：先执行方法然后根据方法返回值判断是否具备权限。
    //例如：查询一个 Admin 对象，在@PostAuthorize 注解中和当前登录的 Admin 对象
    //进行比较，如果不一致，则判断为不能访问。实现“只能查自己”效果。
    //@PostAuthorize("returnObject.data.loginAcct == principal.username")
    //使用 returnObject 获取到方法返回值，使用 principal 获取到当前登录用户的主体对象
    @ResponseBody
    @PostAuthorize("returnObject.data.loginAcct == principal.username")
    @RequestMapping("/admin/test/post/filter.json")
    public ResultEntity<Admin> getAdminById() {

        Admin admin = new Admin();

        admin.setLoginAcct("adminOperator");

        return ResultEntity.successWithData(admin);
    }

    //@PreFilter：在方法执行前对传入的参数进行过滤。只能对集合类型的数据进行过滤。
    @PreFilter(value="filterObject%2==0")
    @ResponseBody
    @RequestMapping("/admin/test/pre/filter")
    public ResultEntity<List<Integer>> saveList(@RequestBody List<Integer> valueList) {
        return ResultEntity.successWithData(valueList);
    }

    //@PostFilter：在方法执行后对方法返回值进行过滤。只能对集合类型的数据进行过滤。



}
